package net.towee.model.repo.impl;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import net.towee.diff.DiffUtils;
import net.towee.diff.Patch;
import net.towee.model.repo.AttachmentIdentity;
import net.towee.model.repo.DocumentData;
import net.towee.model.repo.DocumentPatch;
import net.towee.server.persistence.impl.MongoDbStore;

import com.google.code.morphia.annotations.Entity;
import com.google.code.morphia.annotations.Id;
import com.google.code.morphia.annotations.PostLoad;
import com.google.code.morphia.annotations.Reference;

/**
 * Simple implementation of document patch
 * @author c58
 */
@Entity(MongoDbStore.DOCUMENTS_PATCH_COLLECTION)
public class DocumentPatchImpl implements DocumentPatch {
	@Id private String id;
	private LinkedList<Patch> descPatch;
	private LinkedList<Patch> profilePatch;
	@Reference private List<AttachmentIdentity> addAtt;
	@Reference private List<AttachmentIdentity> removeAtt;
	
	public DocumentPatchImpl() {}
	public DocumentPatchImpl(String id, DocumentData newDoc, DocumentData oldDoc) {
		this.id = id;
		createEmptyFields();
		
		// Create desc patch
		DiffUtils diff = new DiffUtils();
		descPatch = diff.patch_make(newDoc.getDescription(), oldDoc.getDescription());
		
		// Create attachment patch
		for(AttachmentIdentity att : newDoc.getAttachments().getAttachmentList()) {
			if( !oldDoc.getAttachments().contains( att ) )
				removeAtt.add(att);
		}
		
		for(AttachmentIdentity att : oldDoc.getAttachments().getAttachmentList()) {
			if( !newDoc.getAttachments().contains( att ) )
				addAtt.add(att);
		}
		
		// Create profile patch
		profilePatch = diff.patch_make(newDoc.getProfile().toString(), oldDoc.getProfile().toString());
	}
	
	@PostLoad
	private void createEmptyFields() {
		if(descPatch == null)
			descPatch = new LinkedList<Patch>();
		if(profilePatch == null)
			profilePatch = new LinkedList<Patch>();
		if(addAtt == null)
			addAtt = new ArrayList<AttachmentIdentity>();
		if(removeAtt == null)
			removeAtt = new ArrayList<AttachmentIdentity>();
	}
	
	@Override
	public String getId() {
		return id;
	}

	@Override
	public DocumentData patchDocument(DocumentData doc) {
		// Create diff utils
		DiffUtils diff = new DiffUtils();
		
		// Copy document for patching
		DocumentData old = new DocumentDataImpl(doc);
		
		// Patch and set text
		old.setDescription( diff.patch_apply(descPatch, doc.getDescription())[0].toString() );
		
		// Patch and set profile
		old.getProfile().fromString( diff.patch_apply(profilePatch, doc.getProfile().toString())[0].toString() );
		
		// Patch attachments
		for(AttachmentIdentity att : addAtt) 
			old.getAttachments().addAttachment(att);
				
		for(AttachmentIdentity att : removeAtt) 
			old.getAttachments().removeAttachment(att);
				
		return old;
	}
}